<?php

namespace App\Models\BackHome\AuthManage;

use App\Facades\ScarecrowDoLog;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class LoginModel
{
    //用户密码盐值
    protected static $key = "ScarecrowAuthKey";

    //用户Cache缓存KEY前缀
    protected static $cachePrefix = "SET_BACK_USER_INFO_";

    //缓存失效时间 S
    protected static $expireTime = 86400;

    //默认API调用次数
    public static $callNum = 20000;

    //设置请求来源 1:BackHome
    public static $src = 1;

    /**
     * 创建用户的密码
     * @param $userPassword
     * @return array
     */
    public static function createCheckPassword($userPassword) {
        return ModelReturn(RETURN_SUCCESS, '', md5(self::$key . $userPassword . self::$key));
    }

    /**
     * 登录用户
     * @param $userName
     * @param $userPassword
     * @return array
     * @throws \Exception
     */
    public static function LoginUser($userName, $userPassword)
    {
        $userObj = DB::table('sc_user')->where(['username' => $userName])->first();
        if (!$userObj) {
            return ModelReturn(RETURN_FAIL, '用户名或密码错误');
        }
        $userObj = DbObjectToArr($userObj);
        $checkPassword = self::createCheckPassword($userPassword)['data'];

        if ($checkPassword !== $userObj['password']) {
            return ModelReturn(RETURN_FAIL, '用户名或密码错误');
        }

        $tokenInfo = CreateToken($userObj['id']);
        $cacheToken = self::$cachePrefix . $tokenInfo['token'];
        unset($userObj['password']);

        $nowTime = time();
        $expireTime = $nowTime + self::$expireTime;
        $cacheData = [
            'uid'	=>	$userObj['id'],
            'token'	=>	$tokenInfo['token'],
            'expire_time'	=>	$expireTime,
            'update_time'	=>	$nowTime,
            'call_num'		=>	self::$callNum,
            'is_invalid'	=>	0,
            'src'           =>  self::$src,
            'login_time'    =>  $nowTime
        ];

        $userObj['tokenInfo'] = $cacheData;
        //如果需要路由权限，则在此处进行绑定
        $userObj['authList'] = self::getUserAuthList($userObj['id']);
        try {
            Db::beginTransaction();
            $oldToken = DB::table('sc_token_cache')->whereRaw("uid=? AND src=?", [$userObj['id'], self::$src])->first();
            $oldToken = DbObjectToArr($oldToken);
            if ($oldToken) {
                Cache::forget(self::$cachePrefix . $oldToken['token']);
                DB::table('sc_token_cache')->whereRaw("uid=? AND src=?", [$userObj['id'], self::$src])->update($cacheData);
            } else {
                DB::table('sc_token_cache')->insert($cacheData);
            }
            Cache::put($cacheToken, $userObj, self::$expireTime);
            defined('APP_USER_TOKE_SRC') or define('APP_USER_TOKE_SRC', self::$src);
            HandleLog()->addLog('u', ['username' => $userName], '登录了系统', $cacheData['token']);
            if (env("APP_ENV") !== "testing") {
                $cacheData['token'] = $tokenInfo['cryptToken'];
            } else {
                $cacheData['cryptToken'] = $tokenInfo['cryptToken'];
            }

            Db::commit();
            return ModelReturn(RETURN_SUCCESS, '登录成功', $cacheData);
        } catch (\Throwable $e) {
            DB::rollBack();
            if (config('app.debug')) {
                return ModelReturn($e->getCode(), $e->getMessage());
            } else {
                return ModelReturn($e->getCode(), "登录失败");
            }
        }
    }

    /**
     * 获取用户路由权限列表
     * @param $uid
     * @return array
     */
    protected static function getUserAuthList($uid)
    {
        $authList = [
            //			'/api/login_out'
        ];
        return $authList;
    }

    /**
     * @param $token
     * @param $key
     * @param string $default
     * @param bool $msutDb
     * @return array获取用户信息
     */
    public static function getUserInfo($token, $key = '', $default = "", $msutDb = false)
    {
        $cacheToken = self::$cachePrefix . $token;
        if (!$msutDb && Cache::has($cacheToken)) {
            $userInfo = Cache::get($cacheToken);
            if ($userInfo) {
                if ($key) {
                    $keyList = explode('.', $key);
                    $keyList = array_filter($keyList);
                    $tempData = $userInfo;
                    foreach ($keyList as $item) {
                        if (isset($tempData[$item])) {
                            $tempData = $tempData[$item];
                        } else {
                            return ModelReturn(RETURN_SUCCESS, '获取成功', $default);
                        }
                    }
                    return ModelReturn(RETURN_SUCCESS, '获取成功', $tempData);
                } else {
                    return ModelReturn(RETURN_SUCCESS, '获取成功', $userInfo);
                }
            }
        }

        $nowTime = time();
        $userObj = DB::table('sc_token_cache as t1')->leftJoin('sc_user as t2', 't2.id', '=', 't1.uid')->whereRaw("t1.expire_time>{$nowTime} AND t1.call_num>0 AND t1.token=? AND t1.is_invalid=0 AND t1.src=?", [$token, self::$src])->select(['t2.*', 't1.uid', 't1.token', 't1.expire_time', 't1.update_time', 't1.call_num', 't1.is_invalid'])->first();
        if (!$userObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '用户不存在');
        }
        $userObj = DbObjectToArr($userObj);
        unset($userObj['password']);
        $tokenInfo = [
            'uid'	=>	$userObj['uid'],
            'token'	=>	$userObj['token'],
            'expire_time'	=>	$userObj['expire_time'],
            'update_time'	=>	time(),
            'call_num'		=>	$userObj['call_num'],
            'is_invalid'	=>	$userObj['is_invalid']
        ];

        $userObj['tokenInfo'] = $tokenInfo;
        //如果需要路由权限，则在此处进行绑定
        $userObj['authList'] = self::getUserAuthList($userObj['id']);
        Cache::put($cacheToken, $userObj, self::$expireTime);

        $userInfo = $userObj;
        if ($userInfo) {
            if ($key) {
                $keyList = explode('.', $key);
                $keyList = array_filter($keyList);
                $tempData = $userInfo;
                foreach ($keyList as $item) {
                    if (isset($tempData[$item])) {
                        $tempData = $tempData[$item];
                    } else {
                        return ModelReturn(RETURN_SUCCESS, '获取成功', $default);
                    }
                }
                return ModelReturn(RETURN_SUCCESS, '获取成功', $tempData);
            }
        }

        return ModelReturn(RETURN_SUCCESS, '获取成功', $userObj);
    }

    /**
     * 更新token
     * @param $token
     * @return array
     * @throws \Exception
     */
    public static function updateToken($token)
    {
        $userInfo = self::getUserInfo($token);
        if ($userInfo['code'] !== RETURN_SUCCESS) {
            return $userInfo;
        }

        $userObj = $userInfo['data'];
        $newTokenInfo = CreateToken($userObj['id']);
        $expireTime = time() + self::$expireTime;
        $updateTokenInfo = [
            'token'	=>	$newTokenInfo['token'],
            'expire_time'	=>	$expireTime,
            'update_time'	=>	time(),
            'call_num'		=>	self::$callNum,
            'is_invalid'	=>	0,
            'src'           =>  self::$src
        ];

        $info = self::updateTokenCache($token, $updateTokenInfo);
        if ($info['code'] === RETURN_SUCCESS) {
            if (env("APP_ENV") !== "testing") {
                $updateTokenInfo['token'] = $newTokenInfo['cryptToken'];
            } else {
                $updateTokenInfo['cryptToken'] = $newTokenInfo['cryptToken'];
            }
            HandleLog()->addLog('u', $updateTokenInfo, '更新了token');
            return ModelReturn(RETURN_SUCCESS, '更新TOKEN成功', $updateTokenInfo);
        }
        return $info;
    }

    /**
     * 更新token信息
     * @param $token
     * @param array $updateData
     * @param bool $isUpdateDb
     * @return array获取用户信息|array
     * @throws \Exception
     */
    public static function updateTokenCache($token, $updateData = [], $isUpdateDb = true)
    {
        $userInfo = self::getUserInfo($token);
        if ($userInfo['code'] != RETURN_SUCCESS) {
            return $userInfo;
        }

        $userObj = $userInfo['data'];
        $tokenInfo = $userObj['tokenInfo'];
        foreach ($updateData as $key => $value) {
            isset($tokenInfo[$key]) && $tokenInfo[$key] = $value;
        }
        $tokenInfo['update_time'] = time();
        $userObj['tokenInfo'] = $tokenInfo;
        $cacheToken = self::$cachePrefix . $token;
        if (!DB::table('sc_token_cache')->whereRaw("token=? AND src=?", [$token, self::$src])->first()) {
            return ModelReturn(RETURN_FAIL, "更新Token缓存信息失败");
        }

        try {
            Cache::put($cacheToken, $userObj, self::$expireTime);
            $isUpdateDb && DB::table('sc_token_cache')->whereRaw("token=? AND src=?", [$token, self::$src])->update($userObj['tokenInfo']);
            return ModelReturn(RETURN_SUCCESS, '更新成功', $userObj);
        } catch (\Throwable $e) {
            self::LoginOut($token);
            if (config('app.debug')) {
                return ModelReturn($e->getCode(), $e->getMessage());
            } else {
                return ModelReturn($e->getCode(), "更新Token缓存信息失败");
            }
        }
    }

    /**
     * 退出登录
     * @param $token
     * @return array
     * @throws \Exception
     */
    public static function LoginOut($token)
    {
        $cacheToken = self::$cachePrefix . $token;
        Cache::forget($cacheToken);
        DB::table('sc_token_cache')->whereRaw("token=? AND src=?", [$token, self::$src])->update([
            'is_invalid'	=>	1,
            'update_time'	=>	time()
        ]);
        HandleLog()->addLog('d', ['token' => $token], '退出了系统');
        return ModelReturn(RETURN_SUCCESS, '退出登录成功');
    }

    /**
     * 用户注册
     * @param $userName
     * @param $userPwd
     * @return array
     */
    public static function register($userName, $userPwd) {
        $userObj = DB::table('sc_user')->where("username", $userName)->first();
        if ($userObj) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '该登录账户已存在,请修改登录账户进行注册');
        }
        $checkPassword = self::createCheckPassword($userPwd)['data'];
        $insertData = [
            'nike_name' =>  substr($userName, 0, 10),
            'username'  =>  $userName,
            'password'  =>  $checkPassword,
            'is_supper_admin'   =>  0
        ];
        try {
            DB::beginTransaction();
            DB::table('sc_user')->insert($insertData);
            HandleLog()->addLog('i', $insertData, "用户{$userName}注册了账号");
            DB::commit();
            return ModelReturn(RETURN_SUCCESS, '注册成功');
        } catch (\Exception $e) {
            DB::rollBack();
            return ModelReturn($e->getCode(), '注册失败:' . $e->getMessage());
        }
    }

    /**
     * 修改用户密码
     * @param $token
     * @param $oldPwd
     * @param $newPwd
     * @return array
     */
    public static function updatePwd($token, $oldPwd, $newPwd) {
        $userObj = self::getUserInfo($token, 'id');
        if ($userObj['code'] != RETURN_SUCCESS) {
            return $userObj;
        }
        $userId = $userObj['data'];
        $checkPassword = self::createCheckPassword($oldPwd)['data'];
        $userExit = DB::table('sc_user')->whereRaw("id=? AND password=?", [$userId, $checkPassword])->first();
        if (!$userExit) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '用户原始密码错误');
        }

        $newUserPwd = self::createCheckPassword($newPwd)['data'];
        try {
            DB::table('sc_user')->where('id', $userId)->update([
                'is_update_init_pwd'    =>  1,
                'password'              =>  $newUserPwd
            ]);
            HandleLog()->addLog("u", ['userId'=>$userId], '修改了账户密码');
            return ModelReturn(RETURN_SUCCESS, '修改成功');
        } catch (\Throwable $exception) {
            return ModelReturn($exception->getCode(), $exception->getMessage());
        }
    }

    /**
     * 重置用户密码
     * @param $token
     * @param $newPwd
     * @return array
     */
    public static function resetUserPwd($token, $newPwd) {
        $userObj = self::getUserInfo($token);
        if ($userObj['code'] != RETURN_SUCCESS) {
            return $userObj;
        }
        $isAdmin = $userObj['data']['is_supper_admin'] == 0 ? false : true;

        if (!$isAdmin) {
            return ModelReturn(RETURN_CHECK_DATA_DB_FAIL, '无权限进行密码重置,请联系超级管理员进行重置');
        }
        $userId = $userObj['data']['id'];
        $newUserPwd = self::createCheckPassword($newPwd)['data'];
        try {
            DB::table('sc_user')->where('id', $userId)->update([
                'is_update_init_pwd'    =>  1,
                'password'              =>  $newUserPwd
            ]);
            HandleLog()->addLog("u", ['userId'=>$userId], '重置了账户密码');
            return ModelReturn(RETURN_SUCCESS, '修改成功');
        } catch (\Throwable $exception) {
            return ModelReturn($exception->getCode(), $exception->getMessage());
        }
    }
}
